#include "./include/getsym.h"
#include <vector>
#include <sstream>
#include <map>
#include <stack>
using namespace std;


map<string,string> table;
void init_table(string filename) {
  ifstream in;
  in.open(filename);
  string s,s1,s2;
  while(getline(in, s)) {
    stringstream ss(s);
    ss>>s1>>s2;
    table.insert(pair<string,string>(s1,s2));
  }
  in.close();
}

struct formula {
  string left;
  std::vector<string> rights;
  formula(){};
  /*
  *  s的格式类似于
  *  <赋值语句> --  标识符 := <表达式>
  */
  formula(string s) {
    stringstream ss(s);
    ss>>left;
    string temp;
    ss>>temp; //去掉--
    while(ss>>temp) {
      rights.push_back(temp);
    }
  }
  //当使用该条产生式归约时需要弹出状态栈的个数
  int get_ret_len() {
    if(rights[0]!="!")
      return rights.size();
    return 0;
  }
  friend ostream& operator << (ostream & out ,const formula & f) {
    out<<f.left<<"  -->  ";
    for(auto s:f.rights)
      out<<s<<" ";
    out<<endl;
  }
};
std::vector<formula> formulas;
void init_formula(string filename) {
  ifstream in;
  in.open(filename);
  string s;
  while(getline(in, s)) {
    if(s.length())
      formulas.push_back(formula(s));
  }
}

struct action {
  int type; //0代表移进，1代表归约，2代表处acc
  int id;   //产生式编号或状态编号
  action(){};
  action(int n1,int n2) {type=n1;id=n2;};
};

struct status {
  int status_id;
  std::map<string, action> actions;
  status(){};
  status(int id) { status_id = id; }
  void add_to_actions(string s) {
    stringstream ss(s);
    string s1,s2; int n;
    ss>>s1>>s2>>n;
    if(s2=="s") {
      actions.insert(pair<string,action>(s1,action(0,n)));
    } else if(s2=="r"){
      actions.insert(pair<string,action>(s1,action(1,n)));
    } else {
      //成功
      actions.insert(pair<string,action>("any",action(2,n)));
    }
  }

  action next_action(node n) {
    if(actions.count("any")>0) {
      cout<<"Success"<<endl;
      exit(0);
    }
    if(n.type!=SYM_NULL) {
      //终结符
      string s = temp[(int)(n.type)];
      if(table.count(s)>0) {
        if(actions.count(table[s])>0)
          return actions[table[s]];
      }
      return actions[table["SYM_NULL"]];
    } else {
      //非终结符
      if(actions.count(n.id_name)>0)
        return actions[n.id_name];
    }
  }

  friend ostream& operator << (ostream& out , status & stat) {
    out<<"id: "<<stat.status_id<<"\nnumber: "<<stat.actions.size()<<endl;
  }
};
std::vector<status> statuss;
void init_statuss(string filename) {
  ifstream in;
  in.open(filename);
  if(!in.is_open()) {
    cout<<"打开文件"<<filename<<"失败"<<endl;
    exit(0);
  }

  string s; int counter = -1;
  while(getline(in,s)) {
    if(s=="# # #") {
      statuss.push_back(status(++counter));
    } else {
      statuss[counter].add_to_actions(s);
    }
  }

  in.close();
}

void print_stack(std::vector<int> v) {
  for(auto i:v) {
    cout<<i<<" ";
  }
  cout<<endl;
}

int main(int argc, char const *argv[]) {
  //初始化词法分析器
  if(argc!=2)
    return 0;
  analyzer words(argv[1]);

  //初始化映射表
  init_table("./files/table.txt");
  //初始化产生式
  init_formula("./files/新文法.txt");
  //初始化语法分析状态表
  init_statuss("./files/status.txt");


  //开始语法分析
  std::vector<int> v; //状态栈,状态0入栈
  v.push_back(0);
  node n; status cur_stat;  //当前符号，当前栈顶状态
  bool forward = true; //是否移进新符号，在上一个符号被移进后才可以获取新符号
  while(v.size() > 0) {
    print_stack(v);
    cur_stat = statuss[v.back()];  //当前栈顶状态
    if(forward) {
      n = words.get_a_node();
      forward = false;  //暂时不移进新符号
      cout<<n;
    }
    action next = cur_stat.next_action(n);
    if(next.type==0) {
      //移进，新状态入栈
      v.push_back(next.id);
      forward = true; //需要移进下一个符号
    } else {
      //归约,使用某条产生式归约，出栈右部长度，使用新栈顶状态处理n
      int flag = 1;
      while (flag) {
        flag = 0;
        cout<<formulas[next.id];
        for(int i=0;i<formulas[next.id].get_ret_len();i++)
          v.pop_back();
        cur_stat = statuss[v.back()];
        next = cur_stat.next_action(node(SYM_NULL,formulas[next.id].left));
        //如果下一步是移进，移进了事
        if(next.type==0) {
          v.push_back(next.id);
        } else {
          //下一步还是归约，继续循环
          print_stack(v);
          flag = 1;
        }
      }
    }
  }

  return 0;
}
